package com.googlecode.springgameengine.lwjgl;

import com.googlecode.springgameengine.resource.MeshDescriptor;
import com.googlecode.springgameengine.resource.ResourceLoader;
import com.googlecode.springgameengine.resource.ResourceNotLoadableException;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import static org.lwjgl.opengl.GL11.*;
import org.lwjgl.util.vector.Vector3f;

/**
 *
 * @author Maciej
 */
public class LWJGLObjMeshResourceLoader implements ResourceLoader<MeshDescriptor> {

	private static final Log log = LogFactory.getLog(LWJGLObjMeshResourceLoader.class);

	@Override
	public LWJGLMesh load(MeshDescriptor resourceDescriptor) throws ResourceNotLoadableException {
		URL meshURL = getClass().getResource(resourceDescriptor.getFilename());
		if(meshURL == null) {
			log.error(String.format("File [%s] not found!", resourceDescriptor.getFilename()));
			throw new ResourceNotLoadableException(String.format("File [%s] not found!", resourceDescriptor.getFilename()));
		}
		log.info(String.format("Loading [%s]", resourceDescriptor.getFilename()));
		try (BufferedReader reader = new BufferedReader(new FileReader(meshURL.getFile()))) {
			Model m = new Model();
			String line;
			while ((line = reader.readLine()) != null) {
				if (line.startsWith("v ")) {
					float x = Float.valueOf(line.split(" ")[1]);
					float y = Float.valueOf(line.split(" ")[2]);
					float z = Float.valueOf(line.split(" ")[3]);
					m.vertices.add(new Vector3f(x, y, z));
				} else if (line.startsWith("vn ")) {
					float x = Float.valueOf(line.split(" ")[1]);
					float y = Float.valueOf(line.split(" ")[2]);
					float z = Float.valueOf(line.split(" ")[3]);
					m.normals.add(new Vector3f(x, y, z));
				} else if (line.startsWith("f ")) {
					Vector3f vertexIndices = new Vector3f(Float.valueOf(line.split(" ")[1].split("/")[0]),
							Float.valueOf(line.split(" ")[2].split("/")[0]),
							Float.valueOf(line.split(" ")[3].split("/")[0]));
					Vector3f normalIndices = new Vector3f(Float.valueOf(line.split(" ")[1].split("/")[2]),
							Float.valueOf(line.split(" ")[2].split("/")[2]),
							Float.valueOf(line.split(" ")[3].split("/")[2]));
					m.faces.add(new Face(vertexIndices, normalIndices));
				}
			}
			reader.close();
                        int numList = 1;
			int meshList = glGenLists(numList);
			glNewList(meshList, GL_COMPILE);
			{
				glBegin(GL_TRIANGLES);
				for (Face face : m.faces) {
					Vector3f n1 = m.normals.get((int) face.normal.x - 1);
					glNormal3f(n1.x, n1.y, n1.z);
					Vector3f v1 = m.vertices.get((int) face.vertex.x - 1);
					glVertex3f(v1.x, v1.y, v1.z);
					Vector3f n2 = m.normals.get((int) face.normal.y - 1);
					glNormal3f(n2.x, n2.y, n2.z);
					Vector3f v2 = m.vertices.get((int) face.vertex.y - 1);
					glVertex3f(v2.x, v2.y, v2.z);
					Vector3f n3 = m.normals.get((int) face.normal.z - 1);
					glNormal3f(n3.x, n3.y, n3.z);
					Vector3f v3 = m.vertices.get((int) face.vertex.z - 1);
					glVertex3f(v3.x, v3.y, v3.z);
				}
				glEnd();
			}
			glEndList();
			return new LWJGLMesh(meshList, numList);
		} catch (IOException ex) {
			log.error(String.format("Error loading mesh from [%s]!", resourceDescriptor.getFilename()), ex);
			throw new ResourceNotLoadableException(ex);
		}
	}

	public class Model {

		public List<Vector3f> vertices = new ArrayList<>();
		public List<Vector3f> normals = new ArrayList<>();
		public List<Face> faces = new ArrayList<>();
	}

	public class Face {

		public Vector3f vertex = new Vector3f(); // three indices, not vertices or normals!
		public Vector3f normal = new Vector3f();

		public Face(Vector3f vertex, Vector3f normal) {
			this.vertex = vertex;
			this.normal = normal;
		}
	}
}
